#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include "DES.c"
#define MAXLINE 4096


int K_client[64] = { 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0,
                     0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0 };

int size;
char inputTexts[100][65];
int input[100][64];


void intToString(int a[][64], int size, char* sendline) {
    int index = 0;
    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < 64; ++j) {
            sendline[index++] = a[i][j] + 48;
        }
    }
    sendline[index] = '\0';
}

int main(int argc, char** argv){
    //AS通信
    int   ASsockfd, n;
    char  ASsendline[4096];
    struct sockaddr_in  ASservaddr;
    char cipherA[4096];
    char cipherB[4096];
    int cipherAInt[100][64];
    int cipherBInt[100][64];
    int plainA[100][64];
    int plainB[100][64];

    //TGS通信
    int TGSsockfd;
    char TGSsendC[4096];
    char TGSsendD[4096];
    struct sockaddr_in  TGSservaddr;
    //消息C
    char serviceID[9] = "00001111";
    //消息D
    char clientID[4] = "001";
    char timestampTGS[6] = "11100";
    //消息E
    char SSsendE[4096];
    //消息F
    char cipherF[4096];


    //SS通信
    int SSsockfd;
    struct sockaddr_in  SSservaddr;
    int cipherFInt[100][64];
    int plainF[100][64];
    //消息G
    char timestampSS[6] = "00011";
    char SSsendG[4096];
    //消息H
    char SSsendH[4096];


    if( argc > 1){
        printf("usage: ./client \n");
        return 0;
    }

    if( (ASsockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
        return 0;
    }

    memset(&ASservaddr, 0, sizeof(ASservaddr));
    ASservaddr.sin_family = AF_INET;
    ASservaddr.sin_port = htons(8080);
    if( inet_pton(AF_INET, "127.0.0.1", &ASservaddr.sin_addr) <= 0){
        printf("inet_pton error for %s\n",argv[1]);
        return 0;
    }

    if(connect(ASsockfd, (struct sockaddr*)&ASservaddr, sizeof(ASservaddr)) < 0){
        printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }

    printf("======send message to AS server: ======\n");
    fgets(ASsendline, 4096, stdin);
    
    if(send(ASsockfd, ASsendline, strlen(ASsendline), 0) < 0){
        printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }

    printf("======waiting for AS server's respone======\n");
    n = recv(ASsockfd, cipherA, MAXLINE, 0);
    cipherA[n] = '\0';
    printf("消息A：%s\n", cipherA);


    n = recv(ASsockfd, cipherB, MAXLINE, 0);
    cipherB[n] = '\0';
    printf("消息B：%s\n", cipherB);

    close(ASsockfd);

    printf("======关闭ASsockfd======\n");

    for (int i = 0; i < strlen(cipherA); ++i) {
        int k = i / 64;
        int j = i % 64;
        cipherAInt[k][j] = cipherA[i] - 48;
    } 

    int sizeA = strlen(cipherA) / 64;
    for (int i = 0; i < sizeA; ++i) {
        decrypt(cipherAInt[i], K_client, plainA[i]);
    }

    int k_client_tgs[64];
    for (int i = 0; i < 64; ++i) {
        k_client_tgs[i] = plainA[0][i];
    }

    //消息C
    strncat(TGSsendC, serviceID, 9);
    strncat(TGSsendC, cipherB, strlen(cipherB));

    //消息D
    char textD[4096];
    strncat(textD, clientID, 4);
    strncat(textD, timestampTGS, 6);

    size = 1;
    for (int i = 0; i < strlen(textD); ++i) {
        inputTexts[0][i] = textD[i];
    }

    manageText();

    int cipherD[size][64];
    for (int i = 0; i < size; ++i) {
        encrypt(input[i], k_client_tgs, cipherD[i]);
    }

    intToString(cipherD, size, TGSsendD);

    if((TGSsockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
        return 0;
    }

    memset(&TGSservaddr, 0, sizeof(TGSservaddr));
    TGSservaddr.sin_family = AF_INET;
    TGSservaddr.sin_port = htons(8081);
    if( inet_pton(AF_INET, "127.0.0.1", &TGSservaddr.sin_addr) <= 0){
        printf("inet_pton error for %s\n",argv[1]);
        return 0;
    }

    if(connect(TGSsockfd, (struct sockaddr*)&TGSservaddr, sizeof(TGSservaddr)) < 0){
        printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }

    printf("======send message to TGS server: ======\n");
    printf("消息C: %s\n", TGSsendC);
    printf("消息D: %s\n", TGSsendD);
    
    //发送消息C
    if(send(TGSsockfd, TGSsendC, strlen(TGSsendC), 0) < 0){
        printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }

    sleep(2);

    //发送消息D
    if(send(TGSsockfd, TGSsendD, strlen(TGSsendD), 0) < 0){
        printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }

    printf("======waiting for TGS server's respone======\n");
    n = recv(TGSsockfd, SSsendE, MAXLINE, 0);
    SSsendE[n] = '\0';
    printf("消息E：%s\n", SSsendE);


    n = recv(TGSsockfd, cipherF, MAXLINE, 0);
    cipherF[n] = '\0';
    printf("消息F：%s\n", cipherF);

    close(TGSsockfd);
    printf("======关闭TGSsockfd======\n");

    //解密消息F得到k_client_ss
    for (int i = 0; i < strlen(cipherF); ++i) {
        int k = i / 64;
        int j = i % 64;
        cipherFInt[k][j] = cipherF[i] - 48;
    } 

    int sizeF = strlen(cipherF) / 64;
    for (int i = 0; i < sizeF; ++i) {
        decrypt(cipherFInt[i], k_client_tgs, plainF[i]);
    }

    int k_client_ss[64];
    for (int i = 0; i < 64; ++i) {
        k_client_ss[i] = plainF[0][i];
    }

    //消息G
    char textG[4096] = {'\0'};
    strncat(textG, clientID, 4);
    strncat(textG, timestampSS, 6);

    size = 1;
    for (int i = 0; i < strlen(textG); ++i) {
        inputTexts[0][i] = textG[i];
    }

    manageText();

    int cipherG[size][64];
    for (int i = 0; i < size; ++i) {
        encrypt(input[i], k_client_ss, cipherG[i]);
    }

    intToString(cipherG, size, SSsendG);

    if((SSsockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        printf("create socket error: %s(errno: %d)\n", strerror(errno),errno);
        return 0;
    }

    memset(&SSservaddr, 0, sizeof(SSservaddr));
    SSservaddr.sin_family = AF_INET;
    SSservaddr.sin_port = htons(8082);
    if( inet_pton(AF_INET, "127.0.0.1", &SSservaddr.sin_addr) <= 0){
        printf("inet_pton error for %s\n",argv[1]);
        return 0;
    }

    if(connect(SSsockfd, (struct sockaddr*)&SSservaddr, sizeof(SSservaddr)) < 0){
        printf("connect error: %s(errno: %d)\n",strerror(errno),errno);
        return 0;
    }

    printf("======send message to SS server: =======\n");
    printf("消息E: %s\n", SSsendE);
    printf("消息G: %s\n", SSsendG);
    
    //发送消息E
    if(send(SSsockfd, SSsendE, strlen(SSsendE), 0) < 0){
        printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }

    sleep(2);

    //发送消G
    if(send(SSsockfd, SSsendG, strlen(SSsendG), 0) < 0){
        printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
        return 0;
    }

    printf("======waiting for SS server's respone======\n");
    n = recv(SSsockfd, SSsendH, MAXLINE, 0);
    SSsendE[n] = '\0';
    printf("消息H：%s\n", SSsendH);

    close(SSsockfd);
    printf("======关闭SSsockfd======\n");

    //解密消息H并认证
    int cipherHInt[100][64];
    int plainH[100][64];
    for (int i = 0; i < strlen(SSsendH); ++i) {
        int k = i / 64;
        int j = i % 64;
        cipherHInt[k][j] = SSsendH[i] - 48;
    } 

    int sizeH = strlen(SSsendH) / 64;
    for (int i = 0; i < sizeH; ++i) {
        decrypt(cipherHInt[i], k_client_ss, plainH[i]);
    } 

    //提取解密后的消息H中的TS并认证
    int TSval_H = 0;
    for (int i = 0; i < 5; ++i) {
        int a = plainH[0][i+3];
        TSval_H = TSval_H + (a << (4-i));
    }

    int TSval = 0;
    for (int i = 0; i < 5; ++i) {
        int a = timestampSS[i] - 48;
        TSval = TSval + (a << (4-i));
    }

    if (TSval + 1 == TSval_H) {
        printf("======认证成功，SS可以信赖======\n");
    } else {
        printf("======认证失败，SS不可以信赖======\n");
    }
    








    return 0;
}